package com.synergy.stockflow.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.synergy.stockflow.constant.ResultCode;
import com.synergy.stockflow.entity.SysRole;
import com.synergy.stockflow.entity.SysUser;
import com.synergy.stockflow.entity.SysUserRole;
import com.synergy.stockflow.entity.dto.SysUserDTO;
import com.synergy.stockflow.entity.dto.SysUserPwdDTO;
import com.synergy.stockflow.entity.vo.SysUserVO;
import com.synergy.stockflow.exception.BusinessException;
import com.synergy.stockflow.mapper.SysPermissionMapper;
import com.synergy.stockflow.mapper.SysRoleMapper;
import com.synergy.stockflow.mapper.SysUserMapper;
import com.synergy.stockflow.mapper.SysUserRoleMapper;
import com.synergy.stockflow.model.UserDetailsImpl;
import com.synergy.stockflow.repositories.UserDetailsMapper;
import com.synergy.stockflow.service.SysUserService;
import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.log4j.Log4j2;
import org.apache.ibatis.executor.BatchResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Transactional
@Log4j2(topic = "log")
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService, UserDetailsMapper {
    private static final String DEFAULT_PASSWORD = "123456";


    private final SysRoleMapper sysRoleMapper;

    private final SysPermissionMapper sysPermissionMapper;

    @Autowired
    private SysUserRoleMapper sysUserRoleMapper;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private static final String USER_DETAILS_CACHE = "auth:user_details:";

    private static final ObjectMapper objectMapper = new ObjectMapper();


    public SysUserServiceImpl(SysRoleMapper sysRoleMapper, SysPermissionMapper sysPermissionMapper) {
        this.sysRoleMapper = sysRoleMapper;
        this.sysPermissionMapper = sysPermissionMapper;
    }

    @Override
    @Operation(description = "根据用户名查询UserDetails")
    @Cacheable(cacheNames = "auth", key = "#username")
    public UserDetails findUserByUsername(String username) throws UsernameNotFoundException {
        LambdaQueryWrapper<SysUser> ged = new QueryWrapper<SysUser>().lambda().eq(SysUser::getUsername, username);
        ged.ne(SysUser::getDelFlag, 1);
        ged.ne(SysUser::getStatus, 0);
        SysUser user = baseMapper.selectOne(ged);
        if (user == null) {
            throw new UsernameNotFoundException("用户不存在/存在账号异常");
        }
        List<String> roles = sysRoleMapper.selectRoleCodesByUserId(user.getId());
        List<String> perms = sysPermissionMapper.selectPermissionCodesByUserId(user.getId());
        List<String> authorities = new ArrayList<>();
        authorities.addAll(roles);
        authorities.addAll(perms);
        UserDetailsImpl details = new UserDetailsImpl();
        details.setUsername(username);
        details.setPassword(user.getPassword());
        details.setAuthCodes(authorities);
        details.setEnabled(user.getStatus() == 1 && user.getDelFlag() == 0);
        return details;
    }

    @Override
    @Operation(description = "查询当前登陆用户")
    public SysUserVO currentUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if (authentication.getPrincipal() instanceof UserDetailsImpl) {
            UserDetailsImpl principal = (UserDetailsImpl) authentication.getPrincipal();
            LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(SysUser::getUsername, principal.getUsername());
            SysUser user = baseMapper.selectOne(queryWrapper);
            return SysUserVO.fromEntity(user);
        } else {
            return null;
        }
    }

    @Override
    public Boolean saveUser(SysUserDTO dto) {
        LambdaQueryWrapper<SysUser> queryByUsernameWrapper = new LambdaQueryWrapper<>();
        List<SysUser> list = this.list(queryByUsernameWrapper.eq(SysUser::getUsername, dto.getUsername()));
        if (list != null && !list.isEmpty()) {
            throw new BusinessException(ResultCode.FAIL, "该用户名已存在");
        }
        Date date = new Date();
        SysUser user = SysUserDTO.toEntity(dto);
        if (user == null) {
            throw new BusinessException(ResultCode.BUSINESS_EXCEPTION, "用户数据不能为空");
        }
        // 设置默认密码
        user.setPassword(new BCryptPasswordEncoder().encode(DEFAULT_PASSWORD));
        user.setCreateBy(currentUser().getId());
        user.setCreateTime(date);
        user.setDelFlag((byte) 0);
        boolean saved = this.save(user);
        if (!saved) {
            throw new BusinessException(ResultCode.BUSINESS_EXCEPTION, "用户保存失败");
        }
        List<String> roleCodes = dto.getRoleCodes();
        if (roleCodes != null && !roleCodes.isEmpty()) {
            LambdaQueryWrapper<SysRole> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.in(SysRole::getRoleCode, roleCodes);
            List<SysRole> sysRoles = sysRoleMapper.selectList(queryWrapper);
            List<SysUserRole> userRoles = sysRoles.stream().map(sysRole -> {
                SysUserRole userRole = new SysUserRole();
                userRole.setSysUserId(user.getId());
                userRole.setCreateTime(date);
                userRole.setSysRoleId(sysRole.getRoleId());
                return userRole;
            }).collect(Collectors.toList());
            List<BatchResult> results = sysUserRoleMapper.insert(userRoles, 100);
            if (results == null) {
                throw new BusinessException(ResultCode.BUSINESS_EXCEPTION, "用户角色关联保存失败");
            }
        }
        return true;
    }

    @Override
    public Boolean updateUserByUsername(SysUserDTO dto) {
        if (dto == null || dto.getUsername() == null || dto.getUsername().trim().isEmpty()) {
            throw new BusinessException(ResultCode.FAIL, "用户名不能为空");
        }

        String username = dto.getUsername().trim();

        // 1. 查询用户是否存在
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getUsername, username);
        SysUser existingUser = this.getOne(queryWrapper);
        if (existingUser == null) {
            throw new BusinessException(ResultCode.FAIL, "用户【" + username + "】不存在");
        }
        if (!existingUser.getUsername().equals(dto.getUsername())) {
            throw new BusinessException(ResultCode.FAIL, "不允许修改用户名");
        }

        // 2. 构建要更新的用户对象
        Date now = new Date();
        SysUser user = SysUserDTO.toEntity(dto);
        // 其他属性使用原用户对象属性值
        user.setId(existingUser.getId()); // 保留原ID
        user.setUsername(username); // 确保用户名不变或可更新（视业务而定）
        user.setDelFlag(existingUser.getDelFlag());
        user.setCreateTime(existingUser.getCreateTime());
        // 3. 密码处理
        user.setPassword(existingUser.getPassword()); // 保留原密码
        user.setSalt(existingUser.getSalt());
        // 4. 执行用户信息更新
        boolean updated = this.updateById(user);
        if (!updated) {
            throw new BusinessException(ResultCode.BUSINESS_EXCEPTION, "用户信息更新失败");
        }

        // 5. 处理角色：先删除旧角色
        LambdaQueryWrapper<SysUserRole> deleteWrapper = new LambdaQueryWrapper<>();
        deleteWrapper.eq(SysUserRole::getSysUserId, existingUser.getId());
        sysUserRoleMapper.delete(deleteWrapper);

        // 6. 重新分配角色
        List<String> roleCodes = dto.getRoleCodes();
        if (roleCodes == null || roleCodes.isEmpty()) {
            // 默认赋予 ROLE_USER
            roleCodes = Collections.singletonList("ROLE_USER");
        }

        LambdaQueryWrapper<SysRole> roleQueryWrapper = new LambdaQueryWrapper<>();
        roleQueryWrapper.in(SysRole::getRoleCode, roleCodes);
        List<SysRole> sysRoles = sysRoleMapper.selectList(roleQueryWrapper);

        if (sysRoles.isEmpty()) {
            throw new BusinessException(ResultCode.FAIL, "未找到匹配的角色：" + roleCodes);
        }

        List<SysUserRole> userRoles = sysRoles.stream().map(sysRole -> {
            SysUserRole userRole = new SysUserRole();
            userRole.setSysUserId(existingUser.getId());
            userRole.setSysRoleId(sysRole.getRoleId());
            userRole.setCreateTime(now);
            return userRole;
        }).collect(Collectors.toList());

        // 7. 批量插入新角色（使用你的方式）
        List<BatchResult> results = sysUserRoleMapper.insert(userRoles, 100);
        if (results == null) {
            throw new BusinessException(ResultCode.BUSINESS_EXCEPTION, "用户角色关联保存失败");
        }

        log.info("成功根据用户名 [{}] 更新用户信息，操作人: {}", username, currentUser().getId());
        return true;
    }

    @Override
    public Integer updateUserDelFlag(SysUserVO vo) {
        Long id = vo.getId();
        SysUser sysUser = this.getById(id);
        sysUser.setDelFlag((byte) 1);
        return this.updateById(sysUser) ? 1 : 0;
    }

    @Override
    public Integer updateBatchUserDelFlag(List<Long> ids) {
        LambdaUpdateWrapper<SysUser> updateWrapper = new LambdaUpdateWrapper<>();
        if (ids != null && !ids.isEmpty()) {
            updateWrapper.in(SysUser::getId, ids).set(SysUser::getDelFlag, 1);
        } else {
            throw new BusinessException(ResultCode.FAIL, "批量操作失败！");
        }
        boolean updated = this.update(updateWrapper);

        return updated ? 1 : 0;
    }

    @Override
    public Boolean updatePwdByUsername(SysUserPwdDTO dto) {
        SysUserVO currentUserVO = currentUser();
        dto.setUsername(currentUserVO.getUsername());
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getUsername, dto.getUsername());
        SysUser sysUser = this.getOne(queryWrapper);
        if (sysUser == null) {
            throw new BusinessException(ResultCode.BUSINESS_EXCEPTION, "未查询到当前登陆用户");
        }
        PasswordEncoder encoder = new BCryptPasswordEncoder();
        if (!encoder.matches(dto.getOldPassword(), sysUser.getPassword())) {
            throw new BusinessException(ResultCode.BUSINESS_EXCEPTION, "原密码错误");
        }
        if (dto.getNewPassword().equals(dto.getConfirmPassword())) {
            sysUser.setPassword(encoder.encode(dto.getNewPassword()));
        } else {
            throw new BusinessException(ResultCode.BUSINESS_EXCEPTION, "两次密码不相同");
        }
        return this.updateById(sysUser);
    }

    @Override
    public Boolean updateUserInfoByUsername(SysUserDTO dto) {
        SysUserVO currentUserVO = currentUser();
        dto.setUsername(currentUserVO.getUsername());
        LambdaQueryWrapper<SysUser> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysUser::getUsername, dto.getUsername());
        SysUser sysUser = this.getOne(queryWrapper);
        sysUser.setNickname(dto.getNickname());
        sysUser.setPhone(dto.getPhone());
        sysUser.setGender(dto.getGender());
        sysUser.setEmail(dto.getEmail());
        return this.updateById(sysUser);
    }


}
